/*
** $Source: /cvs/cvsroot/inetipc/utils/data_dbg.c,v $
** $Revision: 1.1.1.1 $
** $Date: 2007/10/19 01:52:53 $
**
** File : data_dbg.c
** Date : Historic
*/

#include <sys/types.h>
#include <sys/timeb.h>
#include <sys/time.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <signal.h>

#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>

#include <unistd.h>

#include "data_dbg.h"
#include "ring_buf.h"

// normally when process exits, the shared memory should be deleted
// but for logs, we want to keep it if when the process quit

#define MLINK_DEL_LOGSHM  (0)

#if defined (WIN32)

#include <wchar.h>
#include <windows.h>

/*
** remove directory path for the file path
*/
WCHAR *zStripPathW(WCHAR *path)
{
    WCHAR *base;

    base = wcsrchr(path, L'\\');

    if(base)
    {
        return (base + 1);
    }
    else
    {
        base = path;
    }

    return base;
}

#else // (WIN32)

void  OutputDebugStringA(char *str)
{
	fwrite(str, 1, strlen(str), stdout);
}

#endif // (WIN32)


void dbg_ftime(timeb_t *a)
{
#if defined (WIN32)

    _ftime(a);

#else // !(WIN32)

    struct timeval  tv;

    gettimeofday(&tv, 0);
    
    a->time    = tv.tv_sec;
    a->millitm = tv.tv_usec/1000;

#endif // !(WIN32) : (WIN32)
}

char *zStripPathA(char *path)
{
    char *base;

    base = strrchr(path, '\\');

    if( 0 == base ) base = strrchr(path, '/');

    if(base)
    {
        return (base + 1);
    }
    else
    {
        base = path;
    }

    return base;
}

//////////////////////////////////////////////////////////////////////////////

#define  MY_SHM_KEY  ((key_t)0x0000f0a0)


static int      shmid;
static ring_t  *rb;


int open_dbg_shm(int size)
{
    int       e;
    struct shmid_ds  ds;


    e = shmget(/*IPC_PRIVATE*/MY_SHM_KEY, size, IPC_CREAT|0644);

	if( -1 == e )
	{
		printf(" shmget() error=%d\n", errno);
		return 0;
	}

	shmid = e;

	rb = (ring_t*)shmat(shmid, 0, 0);

	if( 0 == rb )
	{
		printf("shmat() error=%d\n", errno);
	}

	e = shmctl(shmid, IPC_STAT, &ds);

    if(  -1 == e )
	{
		printf("shmctl(IPC_STAT) error=%d\n", errno);

		close_dbg_shm();

		return 0;
	}

	//printf(" shm mode was (%x)\n", ds.shm_perm.mode);

    ds.shm_perm.mode =0666;

	// the shared memeory segment may be created by other process
	// change ownership here

	ds.shm_perm.uid = geteuid();
	ds.shm_perm.gid = getegid();

	e = shmctl(shmid, IPC_SET, &ds);

    if(  -1 == e )
	{
		printf("shmctl(IPC_SET) error=%d\n", errno);

		close_dbg_shm();

		return 0;
	}

	memset(rb, 0, sizeof(*rb));

    rb->end = size - sizeof(*rb);

	return 1;
}

int close_dbg_shm(void)
{
	int e;

    if( 0 == shmid ) return 0;

	if( MLINK_DEL_LOGSHM )
	{
		e = shmctl(shmid, IPC_RMID, 0);

		if( e == -1 )
		{
			printf(" shmctl(IPC_RMID) error=%d\n", errno);

		}
	}
	
	if( rb )
	{
		e = shmdt((void*)rb);

		if( -1 == e )
		{
			printf(" shmdt(%x) error=%d\n", (unsigned int)rb, errno);
		}

		rb = 0;
	}

	return e;
}

////////////////////////////////////////////////////////////////////////////

// a local variable
static int g_debug;

void sig_usr1(int sig)
{
	fflush(stdout);
}

void intr_hdlr(int sig)
{
	if( sig == SIGUSR1 )
	{
		if( g_debug < 4 ) g_debug = 4;
		else if( g_debug < 9 ) g_debug = 9;
		else  g_debug = 1;
	}
	else if( sig == SIGUSR2 )
	{
		g_debug = 0;
	}
	ELOG(" set loglevel = %d\n", g_debug);
}

int set_debug(int v)
{
    signal(SIGUSR1, intr_hdlr);
	signal(SIGUSR2, intr_hdlr);
	g_debug = v;

	return g_debug;
}

void zDbgPrint(int level, char *str, ...)
{
    char *tmpstr;

	msg_t *msg;

    timeb_t    tb;

    struct tm     *tm;

    size_t      len;

    va_list     marker;

    if(g_debug < level ) return;

	/* get system time */
    dbg_ftime(&tb);

    tm = localtime(&tb.time);

	msg = (void*)alloca(1024);

	tmpstr = (char*)msg + sizeof(*msg);

    sprintf(tmpstr, "%.2d:%.2d:%.2d.%.3d ", 
        tm->tm_hour, tm->tm_min, tm->tm_sec, tb.millitm);

    len = strlen(tmpstr);

    va_start(marker, str);

#if defined (WIN32)
    _vsnprintf(tmpstr+len, 1020-len, str, marker);
#else // !(WIN32)
    vsnprintf(tmpstr+len, 1020-len, str, marker);
#endif // !(WIN32) : (WIN32)

    va_end(marker);

	if( 0 == rb )
	{
		/*
		** OutputDebugStringA() may have a 1024 output chars limit
		*/
		OutputDebugStringA(tmpstr);
	}
	else
	{
		msg->len = strlen(tmpstr)+1;
		msg->mid = 0;

		while( 0 == rb_write(rb, msg) )
		{
			rb_yank(rb);
		}

	}
}

/*
**  print a string of given size
*/
void zDbgString(char *str, int size)
{
	char          *tmpstr;

	msg_t         *msg;

    timeb_t    tb;

    struct tm     *tm;

    size_t         len;

	/* get system time */
    dbg_ftime(&tb);

    tm = localtime(&tb.time);

    msg = (void*)alloca(size+32);
	tmpstr = (char*)msg + sizeof(msg_t);

    sprintf(tmpstr, "%.2d:%.2d:%.2d.%.3d ", 
        tm->tm_hour, tm->tm_min, tm->tm_sec, tb.millitm);

    len = strlen(tmpstr);

    memcpy(tmpstr+len, str, size);

    len += size;

    if( '\n' != *(tmpstr+len-1) ) 
    {
        *(tmpstr+len) = '\n';

        len++;
    }

    *(tmpstr+len) = '\0';

	if( 0 == rb )
	{
		OutputDebugStringA(tmpstr);
	}
	else
	{
		msg->len = len+1;
		msg->mid = 0;

		while( 0 == rb_write(rb, msg) )
		{
			rb_yank(rb);
		}
	}
}

///////////////////////////////////////////////////////////////////////////
/*
$Log: data_dbg.c,v $
Revision 1.1.1.1  2007/10/19 01:52:53  linz
no message

Revision 1.3  2005/05/18 03:48:13  linz
add session id

Revision 1.2  2005/05/17 01:19:10  linz
*** empty log message ***

Revision 1.1.1.1  2005/03/06 01:55:30  cvs
imported source

Revision 1.2  2003/11/22 01:31:26  linz
Initial update

*/
